#include "csgdiffnode.h"
#include "csgprimitivenode.h"

CSGDiffNode::CSGDiffNode(Expression &left, Expression &right)
    :CSGNode(0)
{    
    addChild(new CSGPrimitiveNode(left, this));
    addChild(new CSGPrimitiveNode(right, this));
}

CSGDiffNode::CSGDiffNode(CSGNode *left, Expression &right)
    :CSGNode(0)
{
    addChild(left);
    addChild(new CSGPrimitiveNode(right, this));
}

CSGDiffNode::CSGDiffNode(Expression& left, CSGNode *right)
    :CSGNode(0)
{
    addChild(new CSGPrimitiveNode(left, this));
    addChild(right);
}

CSGDiffNode::CSGDiffNode(CSGNode *left, CSGNode *right)
    :CSGNode(0)
{
    addChild(left);
    addChild(right);
}

double CSGDiffNode::eval(double x, double y, double z)
{
    return std::max(((CSGNode*)getChild(0))->eval(x,y,z), -((CSGNode*)getChild(1))->eval(x,y,z));
}

bool CSGDiffNode::emptyTest(StarTestBox *box)
{
    int pos[2];
    ((CSGNode*)getChild(0))->emptyTest(box);
    pos[0] = box->pos;

    if (pos[0] == BOX_OUT)
    {
        return box->isOuter();
    }

    ((CSGNode*)getChild(1))->emptyTest(box);
    pos[1] = box->pos;

    if (box->isInner())
    {
        box->pos = BOX_OUT;
    }
    else if (box->isBoundary())
    {
        box->pos = BOX_BOUNDARY;
    }
    else if (pos[0] == BOX_IN)
    {
        box->pos = BOX_IN;
    }
    else
    {
        box->pos = BOX_BOUNDARY;
    }

    return box->isOuter();
}

bool CSGDiffNode::starTest(StarTestBox *box, double *pt)
{
    int pos[2];

    box->pos = BOX_UNKNOWN;
    ((CSGNode*)getChild(0))->starTest(box, pt);
    pos[0] = box->pos;

    if (pos[0] != BOX_STAR)
    {
        return false;
    }

    box->pos = BOX_UNKNOWN;
    ((CSGNode*)getChild(1))->complementStarTest(box, pt);
    pos[1] = box->pos;

    if (pos[1] == BOX_STAR)
    {
        return true;
    }
    else if (pos[1] == BOX_BOUNDARY)
    {
        box->pos = BOX_BOUNDARY;
    }

    return box->isStar();
}

bool CSGDiffNode::complementStarTest(StarTestBox *box, double *pt)
{
    int pos[2];

    ((CSGNode*)getChild(0))->complementStarTest(box, pt);
    pos[0] = box->pos;

    box->pos = BOX_UNKNOWN;
    ((CSGNode*)getChild(1))->starTest(box, pt);
    pos[1] = box->pos;

    if ((pos[0] == BOX_STAR && pos[1] == BOX_STAR)
            || (pos[0] == BOX_OUT && pos[1] == BOX_STAR)
            || (pos[0] == BOX_STAR && pos[1] == BOX_OUT))
    {
        box->pos = BOX_STAR;
    }
    else if (pos[0] == BOX_BOUNDARY)
    {
        box->pos = BOX_BOUNDARY;
    }

    return box->isStar();
}

bool CSGDiffNode::ptInSet(double *pt)
{
    return ((CSGNode*)getChild(0))->ptInSet(pt) && !((CSGNode*)getChild(1))->ptInSet(pt);
}
